/**
 *  base64.ts
 *
 *  Licensed under the BSD 3-Clause License.
 *    http://opensource.org/licenses/BSD-3-Clause
 *
 *  References:
 *    http://en.wikipedia.org/wiki/Base64
 *
 * @author Dan Kogai (https://github.com/dankogai)
 */
const version = '3.4.5';
/**
 * @deprecated use lowercase `version`.
 */
const VERSION = version;
const _hasatob = typeof atob === 'function';
const _hasbtoa = typeof btoa === 'function';
const _hasBuffer = typeof Buffer === 'function';
const b64ch = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
const b64chs = [...b64ch];
const b64tab = ((a) => {
	let tab = {};
	a.forEach((c, i) => tab[c] = i);
	return tab;
})(b64chs);
const b64re = /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/;
const _fromCC = String.fromCharCode.bind(String);
const _U8Afrom = typeof Uint8Array.from === 'function' ?
	Uint8Array.from.bind(Uint8Array) :
	(it, fn = (x) => x) => new Uint8Array(Array.prototype.slice.call(it, 0).map(fn));
const _mkUriSafe = (src) => src
	.replace(/[+\/]/g, (m0) => m0 == '+' ? '-' : '_')
	.replace(/=+$/m, '');
const _tidyB64 = (s) => s.replace(/[^A-Za-z0-9\+\/]/g, '');
/**
 * polyfill version of `btoa`
 */
const btoaPolyfill = (bin) => {
	// console.log('polyfilled');
	let u32, c0, c1, c2, asc = '';
	const pad = bin.length % 3;
	for (let i = 0; i < bin.length;) {
		if ((c0 = bin.charCodeAt(i++)) > 255 ||
			(c1 = bin.charCodeAt(i++)) > 255 ||
			(c2 = bin.charCodeAt(i++)) > 255)
			throw new TypeError('invalid character found');
		u32 = (c0 << 16) | (c1 << 8) | c2;
		asc += b64chs[u32 >> 18 & 63] +
			b64chs[u32 >> 12 & 63] +
			b64chs[u32 >> 6 & 63] +
			b64chs[u32 & 63];
	}
	return pad ? asc.slice(0, pad - 3) + "===".substring(pad) : asc;
};
/**
 * does what `window.btoa` of web browsers do.
 * @param {String} bin binary string
 * @returns {string} Base64-encoded string
 */
const _btoa = _hasbtoa ? (bin) => btoa(bin) :
	_hasBuffer ? (bin) => Buffer.from(bin, 'binary').toString('base64') :
	btoaPolyfill;
const _fromUint8Array = _hasBuffer ?
	(u8a) => Buffer.from(u8a).toString('base64') :
	(u8a) => {
		// cf. https://stackoverflow.com/questions/12710001/how-to-convert-uint8-array-to-base64-encoded-string/12713326#12713326
		const maxargs = 0x1000;
		let strs = [];
		for (let i = 0, l = u8a.length; i < l; i += maxargs) {
			strs.push(_fromCC.apply(null, u8a.subarray(i, i + maxargs)));
		}
		return _btoa(strs.join(''));
	};
/**
 * converts a Uint8Array to a Base64 string.
 * @param {boolean} [urlsafe] URL-and-filename-safe a la RFC4648 §5
 * @returns {string} Base64 string
 */
const fromUint8Array = (u8a, urlsafe = false) => urlsafe ? _mkUriSafe(_fromUint8Array(u8a)) : _fromUint8Array(u8a);
/**
 * @deprecated should have been internal use only.
 * @param {string} src UTF-8 string
 * @returns {string} UTF-16 string
 */
const utob = (src) => unescape(encodeURIComponent(src));
//
const _encode = _hasBuffer ?
	(s) => Buffer.from(s, 'utf8').toString('base64') :
	(s) => _btoa(utob(s));
/**
 * converts a UTF-8-encoded string to a Base64 string.
 * @param {boolean} [urlsafe] if `true` make the result URL-safe
 * @returns {string} Base64 string
 */
const encode = (src, urlsafe = false) => urlsafe ?
	_mkUriSafe(_encode(src)) :
	_encode(src);
/**
 * converts a UTF-8-encoded string to URL-safe Base64 RFC4648 §5.
 * @returns {string} Base64 string
 */
const encodeURI = (src) => encode(src, true);
/**
 * @deprecated should have been internal use only.
 * @param {string} src UTF-16 string
 * @returns {string} UTF-8 string
 */
const btou = (src) => decodeURIComponent(escape(src));
/**
 * polyfill version of `atob`
 */
const atobPolyfill = (asc) => {
	// console.log('polyfilled');
	asc = asc.replace(/\s+/g, '');
	if (!b64re.test(asc))
		throw new TypeError('malformed base64.');
	asc += '=='.slice(2 - (asc.length & 3));
	let u24, bin = '',
		r1, r2;
	for (let i = 0; i < asc.length;) {
		u24 = b64tab[asc.charAt(i++)] << 18 |
			b64tab[asc.charAt(i++)] << 12 |
			(r1 = b64tab[asc.charAt(i++)]) << 6 |
			(r2 = b64tab[asc.charAt(i++)]);
		bin += r1 === 64 ? _fromCC(u24 >> 16 & 255) :
			r2 === 64 ? _fromCC(u24 >> 16 & 255, u24 >> 8 & 255) :
			_fromCC(u24 >> 16 & 255, u24 >> 8 & 255, u24 & 255);
	}
	return bin;
};
/**
 * does what `window.atob` of web browsers do.
 * @param {String} asc Base64-encoded string
 * @returns {string} binary string
 */
const _atob = _hasatob ? (asc) => atob(_tidyB64(asc)) :
	_hasBuffer ? (asc) => Buffer.from(asc, 'base64').toString('binary') :
	atobPolyfill;
const _decode = _hasBuffer ?
	(a) => Buffer.from(a, 'base64').toString('utf8') :
	(a) => btou(_atob(a));
const _unURI = (a) => _tidyB64(a.replace(/[-_]/g, (m0) => m0 == '-' ? '+' : '/'));
/**
 * converts a Base64 string to a UTF-8 string.
 * @param {String} src Base64 string.  Both normal and URL-safe are supported
 * @returns {string} UTF-8 string
 */
const decode = (src) => _decode(_unURI(src));
/**
 * converts a Base64 string to a Uint8Array.
 */
const toUint8Array = _hasBuffer ?
	(a) => _U8Afrom(Buffer.from(_unURI(a), 'base64')) :
	(a) => _U8Afrom(_atob(_unURI(a)), c => c.charCodeAt(0));
const _noEnum = (v) => {
	return {
		value: v,
		enumerable: false,
		writable: true,
		configurable: true
	};
};
/**
 * extend String.prototype with relevant methods
 */
const extendString = function() {
	const _add = (name, body) => Object.defineProperty(String.prototype, name, _noEnum(body));
	_add('fromBase64', function() {
		return decode(this);
	});
	_add('toBase64', function(urlsafe) {
		return encode(this, urlsafe);
	});
	_add('toBase64URI', function() {
		return encode(this, true);
	});
	_add('toBase64URL', function() {
		return encode(this, true);
	});
	_add('toUint8Array', function() {
		return toUint8Array(this);
	});
};
/**
 * extend Uint8Array.prototype with relevant methods
 */
const extendUint8Array = function() {
	const _add = (name, body) => Object.defineProperty(Uint8Array.prototype, name, _noEnum(body));
	_add('toBase64', function(urlsafe) {
		return fromUint8Array(this, urlsafe);
	});
	_add('toBase64URI', function() {
		return fromUint8Array(this, true);
	});
	_add('toBase64URL', function() {
		return fromUint8Array(this, true);
	});
};
/**
 * extend Builtin prototypes with relevant methods
 */
const extendBuiltins = () => {
	extendString();
	extendUint8Array();
};
const gBase64 = {
	version: version,
	VERSION: VERSION,
	atob: _atob,
	atobPolyfill: atobPolyfill,
	btoa: _btoa,
	btoaPolyfill: btoaPolyfill,
	fromBase64: decode,
	toBase64: encode,
	encode: encode,
	encodeURI: encodeURI,
	encodeURL: encodeURI,
	utob: utob,
	btou: btou,
	decode: decode,
	fromUint8Array: fromUint8Array,
	toUint8Array: toUint8Array,
	extendString: extendString,
	extendUint8Array: extendUint8Array,
	extendBuiltins: extendBuiltins,
};
// makecjs:CUT //
export {
	version
};
export {
	VERSION
};
export {
	_atob as atob
};
export {
	atobPolyfill
};
export {
	_btoa as btoa
};
export {
	btoaPolyfill
};
export {
	decode as fromBase64
};
export {
	encode as toBase64
};
export {
	utob
};
export {
	encode
};
export {
	encodeURI
};
export {
	encodeURI as encodeURL
};
export {
	btou
};
export {
	decode
};
export {
	fromUint8Array
};
export {
	toUint8Array
};
export {
	extendString
};
export {
	extendUint8Array
};
export {
	extendBuiltins
};
// and finally,
export {
	gBase64 as Base64
};
